using System;
using System.IO;
using System.Xml;
using Mediasock.Client.Attribute;
using Mediasock.Client.Service;
using Mediasock.Library.File;

namespace Lifeblog
{
    public class LifeblogService : Service
    {
        private string _server = "http://example.com/services/atom/";
        private Atom _atom;



        public LifeblogService(string serviceId)
            : this(serviceId, new AttributesRecord())
        {
        }

        public LifeblogService(string serviceId, AttributesRecord configRecord)
            : base(serviceId, configRecord)
        {
        }


        public override void SetSession(AttributesCollection sessionAttributesCollection)
        {            
        }

        public override AttributesCollection GetSession()
        {
            return new AttributesCollection(this.makeStatusRecord("11", "Method not implemented."));
        }

        public override AttributesRecord SignIn(AttributesRecord attributes)
        {
            // Ensure necessary information has been provided
            if (!attributes.Contains("auth:user") || !attributes.Contains("auth:pass")
                || string.IsNullOrEmpty(attributes["auth:user"]) || string.IsNullOrEmpty(attributes["auth:pass"]))
                return this.makeStatusRecord("10", "Invalid parameters.");

            string username = attributes["auth:user"];
            string password = attributes["auth:pass"];

            _atom = new Atom(_server, username, password);

            // Perform authentication
            if (_atom.Authenticate())
                return this.makeStatusRecord("0", null);
            else
                return this.makeStatusRecord("42", "Authentication failed.");
        }

        public override AttributesRecord SignOut()
        {
            return this.makeStatusRecord("11", "Method not implemented.");
        }

        public override AttributesCollection FindTaxa(AttributesRecord searchAttributes)
        {
            return new AttributesCollection(this.makeStatusRecord("11", "Method not implemented."));
        }

        public override AttributesCollection MakeTaxa(AttributesRecord taxaAttributes)
        {
            return new AttributesCollection(this.makeStatusRecord("11", "Method not implemented."));
        }

        public override AttributesCollection FindObjects(int index, int count, AttributesRecord searchAttributes, int precache)
        {
            return new AttributesCollection(this.makeStatusRecord("11", "Method not implemented."));
        }

        public override AttributesCollection SendObjects(AttributesCollection objectsAttributesCollection)
        {
            AttributesRecord status = this.makeStatusRecord("0", null);
            int failureCount = 0;

            foreach (AttributesRecord objectRecord in objectsAttributesCollection.Find(AttributesType.Object))
            {
                if (!objectRecord.Contains("file:original") || string.IsNullOrEmpty(objectRecord["file:original"]))
                {
                    objectRecord.Merge(this.makeStatusRecord("10", "File not found"));
                    failureCount++;
                    continue;
                }

                FileStream fileStream = new FileStream(objectRecord["file:original"], FileMode.Open);

                AttributesRecord uploadStatus = this.SendObject(objectRecord, fileStream);

                if (uploadStatus["status:code"] != "0")
                {
                    objectRecord.Merge(uploadStatus);
                    failureCount++;
                }
            }

            // Adding an status denoting the overall success
            if (failureCount > 0)
                status = (failureCount == objectsAttributesCollection.Count) ? this.makeStatusRecord("50", null) : this.makeStatusRecord("03", null);

            objectsAttributesCollection.Add(status);

            return objectsAttributesCollection;
        }

        public override AttributesRecord SendObject(AttributesRecord objectAttributes, System.IO.Stream fileStream)
        {
            string title = objectAttributes.Contains("annotation:title") ? objectAttributes["annotation:title"] : "";

            byte[] data = new byte[fileStream.Length];
            fileStream.Read(data, 0, (int)fileStream.Length);

            try
            {
                string response = _atom.Upload(title, data);

                XmlDocument doc = new XmlDocument();
                doc.LoadXml(response);

                foreach (XmlNode node in doc.FirstChild.NextSibling.ChildNodes)
                {
                    if (node.Name == "id")
                        objectAttributes["object:id"] = node.InnerText;
                }

                objectAttributes.Merge(this.makeStatusRecord("0", null));

                return objectAttributes;
            }
            catch (Exception e)
            {
                if (e.Message.Contains("not authenticated"))
                    return this.makeStatusRecord("41", "Authentication required");
                else
                    return this.makeStatusRecord("50", "Upload failed");
            }
        }

        public override AttributesCollection GetMetadata(AttributesCollection objects)
        {
            return new AttributesCollection(this.makeStatusRecord("11", "Method not implemented."));
        }

        public override AttributesCollection ReceiveObjects(AttributesCollection objectAttributesCollection, string downloadPath)
        {
            return new AttributesCollection(this.makeStatusRecord("11", "Method not implemented."));
        }


        private AttributesRecord makeStatusRecord(string code, string message)
        {
            AttributesRecord status = new AttributesRecord(AttributesType.Sock);
            status["status:code"] = code;
            if (message != null)
                status["status:message"] = message;
            return status;
        }
    }
}
